package org.tp8.ektelesis.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopFieldDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.springframework.stereotype.Service;
import org.tp8.ektelesis.exc.SearchToolException;
import org.tp8.ektelesis.model.SearchResult;
import org.tp8.ektelesis.service.intf.SearchService;

@Service
public class SearchServiceImpl implements SearchService {

	private IndexWriter indexWriter;

	private IndexReader indexReader;

	private IndexSearcher indexSearcher;

	private Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);

	private final static String PROPERTY_PATH = "path";
	private final static String PROPERTY_NAME = "name";

	public void openReader(String path) throws SearchToolException {
		try {
			indexReader = DirectoryReader
					.open(FSDirectory.open(new File(path)));
			indexSearcher = new IndexSearcher(indexReader);
		} catch (IOException e) {
			throw new SearchToolException(e);
		}
		indexSearcher = new IndexSearcher(indexReader);
	}

	public void closeReader() throws SearchToolException {
		try {
			indexReader.close();
		} catch (IOException e) {
			throw new SearchToolException(e);
		}
	}

	public List<SearchResult> search(String value) throws SearchToolException {
		QueryParser parser = new QueryParser(Version.LUCENE_40, PROPERTY_PATH,
				analyzer);
		Query query;
		List<SearchResult> searchResults = new LinkedList<SearchResult>();
		try {
			query = parser.parse(value);
			TopFieldDocs docs = indexSearcher.search(query, 10, Sort.RELEVANCE);
			Document doc;
			SearchResult searchResult;
			for (ScoreDoc scoreDoc : docs.scoreDocs) {
				doc = indexSearcher.doc(scoreDoc.doc);
				searchResult = new SearchResult();
				searchResult.setPath(doc.get(PROPERTY_PATH));
				searchResult.setScore(scoreDoc.score);
				searchResults.add(searchResult);
			}
		} catch (IOException | ParseException e) {
			throw new SearchToolException(e);
		}

		return searchResults;
	}

	public void openWriter(String path) throws SearchToolException {
		File indexFile = new File(path);
		boolean exists = indexFile.exists();
		Directory dir;
		try {
			dir = FSDirectory.open(indexFile);
		} catch (IOException e) {
			throw new SearchToolException(e);
		}
		Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);
		IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_40,
				analyzer);
		if (exists) {
			iwc.setOpenMode(OpenMode.CREATE);
		} else {
			iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
		}
		iwc.setRAMBufferSizeMB(10.0);
		try {
			indexWriter = new IndexWriter(dir, iwc);
		} catch (IOException e) {
			throw new SearchToolException(e);
		}
	}

	public void closeWriter() throws SearchToolException {
		try {
			indexWriter.forceMerge(1);
			indexWriter.close();
		} catch (IOException e) {
			throw new SearchToolException(e);
		}
	}

	@Override
	public void index(File file) throws SearchToolException {
		Document doc = new Document();
		Field pathField = new StringField(PROPERTY_PATH, file.getPath(),
				Field.Store.YES);
		Field nameField = new StringField(PROPERTY_NAME, file.getName(),
				Field.Store.YES);
		doc.add(pathField);
		doc.add(nameField);
		try {
			System.out.println("Indexing: " + file.getPath());
			indexWriter.addDocument(doc);
		} catch (IOException e) {
			throw new SearchToolException(e);
		}

		File[] subFiles = file.listFiles();
		if (subFiles != null) {
			for (File subFile : subFiles) {
				index(subFile);
			}
		}

	}

	@Override
	public void clearIndeces() {

	}

}
